package org.jheuristics.ga.operators.reproductors;

import java.util.List;

import org.epanetgrid.otimizacao.util.OtimizacaoUtil;
import org.jheuristics.Individual;
import org.jheuristics.ga.GAConfig;
import org.jheuristics.ga.GAStatus;
import org.jheuristics.ga.operators.Probability;
import org.jheuristics.ga.operators.Reproductor;
import org.jheuristics.ga.operators.reproductors.funcionalidades.IListXOver;


/**
 * TODO
 *
 * @author Marcell Manfrin, marcell@ourgrid.org, Jan 9, 2006
 */
public class GensListOnePointXOver extends AbstractXOver {

	private IListXOver listXOver;

	/**
	 * TODO
	 *
	 * @param probability
	 * @param maxTryOuts
	 */
	public GensListOnePointXOver(Probability probability, int maxTryOuts, IListXOver listXOver) {
		super(probability, maxTryOuts);
		this.listXOver = listXOver;
	}

	/**
	 * TODO
	 *
	 * @param decoretedReproductor
	 * @param probability
	 * @param tryOuts
	 */
	public GensListOnePointXOver(Reproductor decoretedReproductor, Probability probability, int tryOuts, IListXOver listXOver) {
		super(decoretedReproductor, probability, tryOuts);
		this.listXOver = listXOver;
	}

	/**
	 * TODO
	 *
	 * @param parents
	 * @param status
	 * @param config
	 * @return
	 * @see org.jheuristics.ga.operators.reproductors.AbstractXOver#xover(org.jheuristics.Individual[], org.jheuristics.ga.GAStatus, org.jheuristics.ga.GAConfig)
	 */
	protected Individual[] xover(Individual[] parents, GAStatus status, GAConfig config) {
		if (!parents[0].equals(parents[1])) {
			return doXOver(parents[0], parents[1], chooseXOverPoints(parents[0], parents[1], status, config), status, config);
		}
		logger.debug("Cruzamento não será efetuado (pais iguais).\n");
		return new Individual[] {parents[0], parents[1]};
	}

	/**
	 * TODO
	 *
	 * @param parent1
	 * @param parent2
	 * @param status
	 * @param config
	 * @return
	 */
	protected int[] chooseXOverPoints(Individual parent1, Individual parent2, GAStatus status, GAConfig config) {
		int maxPoint = ((List) parent1.getGens()).size();
		//Garantindo que o tamanho nao vai passar do tamanho do numero maximo de gens
		return new int[] { Math.min(config.getRandomGenerator().nextInt(maxPoint-1)+1, maxPoint-1)};
	}

	/**
	 * TODO
	 *
	 * @param parent1
	 * @param parent2
	 * @param object
	 * @param status
	 * @param config
	 * @return
	 */
	protected Individual[] doXOver(Individual parent1, Individual parent2, int[] xpoints, GAStatus status, GAConfig config) {
//		List gensParent1 = (List) parent1.getGens();
//		List gensParent2 = (List) parent2.getGens();
		int xpoint = xpoints[0];
//		int intervalos = gensParent1.size();
//		List gensChild1 = new ArrayList(intervalos);
//		List gensChild2 = new ArrayList(intervalos);

//		for (int i = 0; i < xpoint; i++) {
//		gensChild1.add(i, gensParent1.get(i));
//		gensChild2.add(i, gensParent2.get(i));
//		}
//		for (int i = xpoint; i < intervalos; i++) {
//		gensChild1.add(i, gensParent2.get(i));
//		gensChild2.add(i, gensParent1.get(i));
//		}


//		IndividualsFactory factory = config.getIndividualsFactory();
//		Individual child1 = factory.createSpecificIndividual(gensChild1, config);
//		Individual child2 = factory.createSpecificIndividual(gensChild2, config);


		Individual[] result = this.listXOver.doXOver(parent1, parent2, xpoints, status, config);
		try{
			this.log(xpoint, result);
		}catch (Exception e) {
			//nao foi possivel logar
		}

		return result;
	}

	private void log(int xpoint, Individual[] children) {
		StringBuffer buf = new StringBuffer();

		buf.append("Ponto de corte: ");
		buf.append(xpoint+1);
		buf.append("\n");

		for (int i = 0; i < children.length; i++) {
			buf.append("Filho "+(i+1)+": \n");
//			buf.append(OtimizacaoUtil.gensToString((List)children[i].getGens()));
			buf.append(OtimizacaoUtil.format(children[i]));
			buf.append("\n");
		}

		logger.debug(buf);
	}

}
